package cn.zhxu.toys.util;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;



public class RsaUtils {

	//非对称密钥算法
    public static final String ALGORITHM = "RSA";


    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     */
    private static final int DEFAULT_KEY_SIZE = 1024;

    
    
    public static class RsaKey {
    	
    	
    	private final PublicKey publicKey;
    	private final PrivateKey privateKey;
    	
    	private byte[] publicKeyBytes;
    	private byte[] privateKeyBytes;


		public RsaKey(PublicKey publicKey, PrivateKey privateKey) {
			this.publicKey = publicKey;
			this.privateKey = privateKey;
		}

		public PublicKey getPublicKey() {
			return publicKey;
		}

		public PrivateKey getPrivateKey() {
			return privateKey;
		}

		public byte[] getPublicKeyBytes() {
			if (publicKeyBytes == null) {
				publicKeyBytes = publicKey.getEncoded();
			}
			return publicKeyBytes;
		}

		public byte[] getPrivateKeyBytes() {
			if (privateKeyBytes == null) {
				privateKeyBytes = privateKey.getEncoded();
			}
			return privateKeyBytes;
		}
    	
    }
    
    
    public static RsaKey generateKey() {
    	return generateKey(DEFAULT_KEY_SIZE);
    }
    
    /**
     * 初始化密钥对
     *
     * @return Map 甲方密钥的Map
     */
    public static RsaKey generateKey(int keySize) {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator;
		try {
			keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("实例化RSA密钥生成器异常：", e);
		}
        //初始化密钥生成器
        keyPairGenerator.initialize(keySize);
        //生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //甲方公钥
        PublicKey publicKey = keyPair.getPublic();
        //甲方私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //将密钥存储在map中
        return new RsaKey(publicKey, privateKey);
    }


    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        return encryptByPrivateKey(data, privateKey);
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param privateKey 密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {
        //数据加密
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key      公钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
        return encryptByPublicKey(data, key, ALGORITHM);
    }

    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key      公钥
     * @param algorithm 规则 支持如下
     *          RSA/ECB/RSA_NO_PADDING
     *          RSA/ECB/RSA_PKCS1_PADDING
     *          RSA/ECB/RSA_PKCS1_OAEP_PADDING
     *          RSA/ECB/OAEPWithSHA-1AndMGF1Padding
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key, String algorithm) throws Exception {
        if (algorithm == null
                || algorithm.equals("")) {
            throw new IllegalArgumentException("algorithm can not be null");
        }
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        return encryptByPublicKey(data, publicKey, algorithm);
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param publicKey  公钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, PublicKey publicKey, String algorithm) throws Exception {
        //数据加密
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }
    
    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        return decryptByPrivateKey(data, privateKey);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param privateKey 私钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {
        //数据解密
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }
    
    
    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  公钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        return decryptByPublicKey(data, publicKey);
    }

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param publicKey 公钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, PublicKey publicKey) throws Exception {
        //数据解密
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }
	
}
